package io.renren.modules.weixin.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.renren.common.utils.*;
import io.renren.modules.weixin.config.WXConfig;
import io.renren.modules.weixin.entity.BaseToken;
import io.renren.modules.weixin.message.BaseReq;
import io.renren.modules.weixin.message.reqMsg.BaseReqMsg;
import io.renren.modules.weixin.message.reqevent.BaseReqEvent;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @Author: zhangxinlin
 * @Description:
 * @Date: Create in 15:14 2018/1/23
 * @Modified By：
 */
@Component
public class WeiXinUtils {
    private static Logger logger = LoggerFactory.getLogger(WeiXinUtils.class);

    @Autowired
    private WXConfig wxConfig;

    @Autowired
    private RedisUtils redisUtils;

    public static class WEIXIN{
        //获取access_token 接口路径
        public static String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
        public static String GET_JS_API_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
        public static final String BASE_TOKEN_KEY = "access_token";
        public static final String JS_API_TICKET_KEY = "jsapiTicket";

    }

    /**
     * @Author: zhangxinlin
     * @Description:
     * @param 
     * @Date: 16:30 2018/1/23
     */
    public String getBaseTokenFromWX(){
        try{
            String param = "grant_type=client_credential&appid="+ wxConfig.getAppId()+"&secret="+wxConfig.getSecret();
            String tokenStr = OKHttpUtils.get(WEIXIN.GET_ACCESS_TOKEN_URL+"?"+ param);
            BaseToken baseToken =  (BaseToken) JSON.parseObject(tokenStr, BaseToken.class);
            logger.info("从微信获取全局token如下：{}",baseToken.toString());
            return baseToken.getAccess_token();
        }catch (Exception e){
            logger.error("从微信获取全局token出错");
        }
        return null;
    }

    /**
     * @Author: zhangxinlin
     * @Description:
     * @param baseToken 微信公众号全局token
     * @Date: 16:35 2018/1/23
     */
    public String getJSAPITicketFromWX(String baseToken){
        String ticket = null;
        try{
            if(StrUtil.isNotBlank(baseToken)){
                String ticketStr = OKHttpUtils.get(WEIXIN.GET_JS_API_TICKET_URL+"?"+"access_token="+baseToken+"&type=jsapi");
                JSONObject json = JSONObject.parseObject(ticketStr);
                ticket = (String)json.get("ticket");
            }
        }catch (Exception e){
            logger.error("从微信获取JSAPI TICKET 出错");
        }
        return ticket;
    }

    /**
     * @Author: zhangxinlin
     * @Description: 获取token
     * @Date: 17:49 2018/1/23
     */
    public String getAccessToken(){
        try{
            if(redisUtils.hasKey(WEIXIN.BASE_TOKEN_KEY)){
                return redisUtils.get(WEIXIN.BASE_TOKEN_KEY);
            }else{
                String accessToken = getBaseTokenFromWX();
                redisUtils.set(WeiXinUtils.WEIXIN.BASE_TOKEN_KEY,accessToken, DateUtils.Time.HOUR*2);
                return accessToken;
            }
        }catch (Exception e){
            logger.error("获取token出错");
            return null;
        }
    }

    /**
     * @Author: zhangxinlin
     * @Description: 获取jsApiTicket
     * @Date: 18:01 2018/1/23
     */
    public String getJSAPITicket(){
        try{
            if(redisUtils.hasKey(WEIXIN.JS_API_TICKET_KEY)){
                return redisUtils.get(WEIXIN.JS_API_TICKET_KEY);
            }else{
                String ticket = getJSAPITicketFromWX(getAccessToken());
                redisUtils.set(WeiXinUtils.WEIXIN.JS_API_TICKET_KEY,ticket,DateUtils.Time.HOUR*2);
                return ticket;
            }
        }catch (Exception e){
            logger.error("获取jsapiticket 出错");
            return null;
        }
    }

    /**
     * @Author: zhangxinlin
     * @Description: 根据微信传过来的消息xml 转换成对应的消息bean
     * @Date: 20:49 2018/1/24
            */
    public static BaseReqMsg buildReqMsg(String msgType, Dom4jHelper dom4jHelper, String prifxReqMsgBean){
        try {
            Map<String,String> map = dom4jHelper.getAllElements();
            Class<?> clazz = Class.forName(prifxReqMsgBean+ StringUtils.capitalize(msgType)+"ReqMsg");
            BaseReqMsg msg = (BaseReqMsg) clazz.newInstance();
            //获取class及其父类的所有字段
            List<Field> fieldList = findAllFields(clazz);
            //设置对象属性
            fieldList.stream().forEach(x->{
                try {
                    setFieldVlaue(msg,x,dom4jHelper.getElementValue(StringUtils.capitalize(x.getName())));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            return msg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @Author: zhangxinlin
     * @Description: 根据微信传过来的xml 转换成对应的消息bean
     * @Date: 20:49 2018/1/24
     */
    public static BaseReqEvent buildReqEvent(String msgType, Dom4jHelper dom4jHelper, String prifxReqMsgBean){
        try {
            Map<String,String> map = dom4jHelper.getAllElements();
            Class<?> clazz = Class.forName(prifxReqMsgBean+ StringUtils.capitalize(msgType));
            BaseReqEvent msg = (BaseReqEvent) clazz.newInstance();
            //获取class及其父类的所有字段
            List<Field> fieldList = findAllFields(clazz);
            //设置对象属性
            fieldList.stream().forEach(x->{
                try {
                    setFieldVlaue(msg,x,dom4jHelper.getElementValue(StringUtils.capitalize(x.getName())));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            return msg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Author: zhangxinlin
     * @Description: 获取一个类 及其父类的所有字段
     * @Date: 21:02 2018/1/24
     */
    protected static List<Field> findAllFields(Class c){
        List<Field> resultList = new LinkedList<>();
        while (!Object.class.equals(c)){
            resultList.addAll(Arrays.asList(c.getDeclaredFields()));
            c = c.getSuperclass();
        }
//        Class parent = c.getSuperclass();
//        Arrays.stream(parent.getDeclaredFields()).forEach(x->{
//            resultList.add(x);
//        });
//        Arrays.stream(c.getDeclaredFields()).forEach(x->{
//            resultList.add(x);
//        });
        return resultList;

    }

    /**
     * @Author: zhangxinlin
     * @Description: 设置对象的字段值
     * @Date: 21:13 2018/1/24
     */
    protected static void setFieldVlaue(Object obj, Field field, String value)
            throws Exception {
        logger.info("setFieldVlaue,field:"+field.getName()+"value:"+value);
        field.setAccessible(true);
        if (field.getType() == boolean.class
                || field.getType() == Boolean.class) {
            if (value.getClass() == String.class) {
                String str = (String) value;
                if (str.equalsIgnoreCase("true")) {
                    field.set(obj, true);
                } else if (str.equalsIgnoreCase("false")) {
                    field.set(obj, false);
                }
            } else {
                field.set(obj, Integer.parseInt(value) == 1);
            }
        } else if (field.getType() == int.class
                || field.getType() == Integer.class) {
            if (field.getType() == int.class && value == null) {
                field.set(obj, 0);
            } else {
                field.set(obj, Integer.parseInt(value));
            }
        } else if (field.getType() == long.class
                || field.getType() == Long.class) {
            if (field.getType() == long.class && value == null) {
                field.set(obj, 0);
            } else {
                field.set(obj, Long.parseLong(value));
            }

        } else if (field.getType() == double.class
                || field.getType() == Double.class) {
            if (field.getType() == double.class && value == null) {
                field.set(obj, 0d);
            } else {
                field.set(obj, Double.parseDouble(value));
            }
        } else if (field.getType() == float.class
                || field.getType() == Float.class) {
            if (field.getType() == float.class && value == null) {
                field.set(obj, 0f);
            } else {
                field.set(obj, Float.parseFloat(value));
            }
        } else if (field.getType() == short.class
                || field.getType() == Short.class) {
            if (field.getType() == short.class && value == null) {
                field.set(obj, 0);
            } else {
                field.set(obj, Short.parseShort(value));
            }
        } else if (field.getType() == byte.class
                || field.getType() == Byte.class) {
            if (field.getType() == byte.class && value == null) {
                field.set(obj, 0);
            } else {
                field.set(obj, Byte.parseByte(value));
            }
        } else if (field.getType() == String.class) {
            field.set(obj, value);
        } else {
            throw new Exception(field.getType().getName()
                    + ":type not support for:" + value);
        }
    }


}
